precision mediump float;

attribute float a_index;

uniform float u_size;
uniform float u_time;
uniform float u_total;
uniform float u_height;

varying float v_opacity;

float random(vec2 st) {
    return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123);
}

// 经典的 Perlin 噪声函数
vec2 fade(vec2 t) {
    return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);
}

float grad(int hash, vec2 p) {
    int h = hash & 7;
    float u = h < 4 ? p.x : p.y;
    float v = h < 4 ? p.y : p.x;
    return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
}

float perlinNoise(vec2 p) {
    vec2 i = floor(p);
    vec2 f = fract(p);
    vec2 u = fade(f);

    int a = int(i.x) + int(i.y) * 57;
    int b = a + 1;

    float res = mix(mix(grad(a, f), grad(b, f - vec2(1.0, 0.0)), u.x), mix(grad(a + 57, f - vec2(0.0, 1.0)), grad(b + 57, f - vec2(1.0, 1.0)), u.x), u.y);

    return res;
}

void main() {
    gl_PointSize = u_size;
    vec3 new_position = position;

    float show_point = u_total * u_time * 0.8;

    if(show_point > a_index) {
        v_opacity = 1.0;
    } else {
        v_opacity = 0.0;
    }

    float frequency = 0.2;
    float speed = 10.;
    float range = u_height;
    float max_height = 80000. + u_height * random(vec2(a_index, u_time));
    float fall_speed = 80000.;
    float fall_delay = a_index * 0.006;

    float fall_height = max(0.1, max_height - (u_time - fall_delay) * fall_speed);

    // z_offset * range * noise
    if(fall_height > 0.1) {
        new_position.z = fall_height;
    } else {
        float normalized_index = mod(a_index, u_total) / u_total;
        float z_offset = sin((u_time * speed + normalized_index * u_total) * frequency);

        z_offset = (z_offset + 1.) / 2.;

        float noise = perlinNoise(vec2(normalized_index * 10., u_time * 0.1));

        noise = (noise + 1.) / 2.;

        float height = z_offset * range * noise + fall_height;
        new_position.z = height;
    }

    gl_Position = projectionMatrix * modelViewMatrix * vec4(new_position, 1.0);
}